/*
    * Copyright (c) 2024 Hunan OpenValley Digital Industry Development Co., Ltd.
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    *     http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
 */

#include "send_manager.h"

#include <cstdlib>
#include <limits.h>
#include <sys/stat.h>
#include <unistd.h>
#include <iostream>  
#include <fstream>  
#include <cstring>
#include <thread>
#include <chrono>
#include <sys/time.h>
#include <ctime>
#include <mutex>
#include <condition_variable>
#include <fcntl.h>

#include "device_manager.h"
#include "session.h"
#include "softbus_bus_center.h"
#include "softbus_error_code.h"
#include "os_account_manager.h"
#include "sandbox_helper.h"
#include "directory_ex.h"
#include "nlohmann/json.hpp"
#include "file_hash.h"
#include "jsonUtil.hpp"
#include "file_share_config.h"
#include "userfile_client.h"
#include "iservice_registry.h"
#include "system_ability_definition.h"
#include "media_file_utils.h"
#include "mimetype_utils.h"
#include "token_setproc.h"
#include "tokenid_kit.h"
#include "accesstoken_kit.h"
#define ORIGIN_UUID 0xFDEE

using namespace OHOS::Media;
using namespace OHOS::Security::AccessToken;
namespace OHOS {
namespace FileShare {
namespace {
    const int32_t PUBLISH_ID = 4082;
    const std::string PKG_NAME = "FileShareService";
    constexpr int OPEN_SESSION_RETRY_INTERVAL_MS = 100;
    constexpr int SEARCH_RETRY_INTERVAL_MS = 1000;
    constexpr int OPEN_SESSION_RETRY_TIMES = 10 * 10;
    constexpr int GET_DEVICE_RETRY_TIMES = 5;
    constexpr int GET_NAME_RETRY_TIMES = 3;
    constexpr int LOG_SPAN = 10;
    constexpr int DEFAULT_USER_ID = 100;
    constexpr int DEC_TO_PERCENT = 100;
    constexpr double S_TO_MS = 1000.0;
    constexpr int DEVICE_ID_SIZE_MAX = 256;
    const char *SESSION_PKG_NAME = "com.ohos.plrdtest.hongyan";
    const char *SESSION_NAME_SERVICE = "com.ohos.plrdtest.hongyan.JtOpenFileSession";
    const char *SESSION_NAME_CLIENT = "com.ohos.plrdtest.hongyan.JtOnOpenFileSession";
    const char *GROUP_ID = "GROUP_ID";
    const char *CURRENT_USER_ID = "<currentUserId>";
    const std::string STORAGE_DEFAULT_PATH = "/mnt/hmdfs/<currentUserId>/account/device_view/local/files/Docs/Share";
    const std::string RESOURCE_INPUT_FILE_PREFIX = "input_";
    const std::string RESOURCE_OUTPUT_FILE_PREFIX = "output_";
    const std::string SYNC_SEND_TASK_SUCCESS = "success";
    const std::string SYNC_SEND_TASK_FAIL = "fail";
    const std::string MEDIA_SHARE_ALBUM_NAME = "分享";
    constexpr uint64_t SYSTEM_APP_MASK = (static_cast<uint64_t>(1) << 32);
    std::atomic<bool> g_openFlag_send(false);
    std::atomic<bool> g_openFlag_recv(false);
    std::atomic<bool> g_recvFlag(false);
}
static struct timeval send_start_time {};
static struct timeval send_end_time {};

static struct timeval recv_start_time {};
static struct timeval recv_end_time {};
static uint64_t lastBytesUpload_send = 0;
static uint64_t lastBytesUpload_recv = 0;

static std::mutex g_syncMutex;
static std::condition_variable g_syncCondition;
static std::string g_syncResult;

static SendState g_sendState = SendState::UNKNOWN;

class DeviceInitCallBack : public DistributedHardware::DmInitCallback {
    void OnRemoteDied() override {
        LOGI("DeviceInitCallBack OnRemoteDied");
    }
};

SendManager &SendManager::GetInstance()
{
    static SendManager instance;
    return instance;
}

static int GetSinkUserId()
{
    std::vector<int32_t> ids;
    int ret = AccountSA::OsAccountManager::QueryActiveOsAccountIds(ids);
    if (ret == ERR_OK && !ids.empty()) {
        return ids[0];
    }
    return DEFAULT_USER_ID;
}

static std::string GetSinkStoragePath()
{
    std::string userId = std::to_string(GetSinkUserId());
    std::string uri = FileShareConfig::GetInstance().GetStoragePath();
    std::string physicalPath;
    int ret = AppFileService::SandboxHelper::GetPhysicalPath(uri, userId, physicalPath);
    if (ret != ERR_OK) {
        LOGW("GetPhysicalPath return %{public}d, uri: %{public}s, userId: %{public}s", ret, uri.c_str(), userId.c_str());
        physicalPath = ReplaceStr(STORAGE_DEFAULT_PATH, CURRENT_USER_ID, userId);
    }
    LOGI("storage path is %{public}s", physicalPath.c_str());
    return physicalPath;
}

static std::string Rename(const std::string &storagePath, const std::string &name, bool isFile = true)
{
    std::string str = "";
    std::string ext = "";
    if (isFile) {
        std::string::size_type pos = name.rfind(".");
        if (pos == std::string::npos) {
            str = name;
        } else {
            str = name.substr(0, pos);
            ext = name.substr(pos);
        }
    } else {
        str = name;
    }

    std::string path = IncludeTrailingPathDelimiter(storagePath) + name;
    int cnt = 0;
    while (access(path.c_str(), F_OK) == 0) {
        cnt++;
        path = IncludeTrailingPathDelimiter(storagePath) + str + "(" + std::to_string(cnt) + ")" + ext;
    }
    return (cnt > 0) ? (str +  "(" + std::to_string(cnt) + ")" + ext) : name;
}

// recv callback
static int OnRenameFile(int sessionId, const char *storagePath, const char *fileName, char *newFileName, int maxFileNameLen)
{
    std::string name = Rename(storagePath, fileName);
    int ret = strcpy_s(newFileName, maxFileNameLen, name.c_str());
    if (ret != 0) {
        LOGE("rename file failed, ret is %{public}d", ret);
        (void)strcpy_s(newFileName, maxFileNameLen, fileName);
    }
    LOGI("rename hook, storagePath = %{public}s, fileName = %{public}s, newFileName = %{public}s", storagePath, fileName, newFileName);
    SendManager::GetInstance().UpdateFileInfo(sessionId, storagePath, fileName, newFileName);
    return SOFTBUS_OK;
}

static int OnSessionOpened_recv(int sessionId, int result)
{
    int dataType = TYPE_BUTT;
    GetSessionOption(sessionId, SESSION_OPTION_DATA_TYPE, &dataType, sizeof(uint32_t));
    LOGI("session opened, sesison id = %{public}d, result = %{public}d, dataType = %{public}d", sessionId, result, dataType);
    if (result == SOFTBUS_OK && dataType == TYPE_FILE) {
        g_openFlag_recv.store(true, std::memory_order_relaxed);
        g_recvFlag.store(false, std::memory_order_relaxed);
        SendManager::GetInstance().NotifyEvent(sessionId, SendType::SINK, SendState::UNKNOWN);
        g_sendState = SendState::UNKNOWN;
        char networkId[DEVICE_ID_SIZE_MAX];
        int ret = ::GetPeerDeviceId(sessionId, networkId, DEVICE_ID_SIZE_MAX);
        if (ret != SOFTBUS_OK) {
            LOGE("GetPeerDeviceId failed, error = %{public}d", ret);
            return ret;
        }
        if (!SendManager::GetInstance().ReadySinkSession(networkId, sessionId)) {
            LOGE("can't ready, close session");
            return FS_SEND_FILE_FAILED;
        }
    }
    return result;
}

static void OnSessionClosed_recv(int sessionId)
{
    int dataType = TYPE_BUTT;
    GetSessionOption(sessionId, SESSION_OPTION_DATA_TYPE, &dataType, sizeof(uint32_t));
    LOGI("session closed, session id = %{public}d, dataType = %{public}d", sessionId, dataType);
    if (dataType == TYPE_FILE) {
        g_openFlag_recv.store(false, std::memory_order_relaxed);
        if (g_sendState == SendState::PROCESSING) {
            LOGI("remote device cancel send file.");
            SendManager::GetInstance().NotifyEvent(sessionId, SendType::SINK, SendState::CANCEL, 0 , 0);
            g_sendState = SendState::CANCEL;
        }
        SendManager::GetInstance().RemoveSinkSessionInfo(sessionId);
    }
}

static void OnBytesReceived_recv(int sessionId, const void* data, unsigned int dataLen)
{
   LOGI("DataBytesReceived,sesison id = %{public}d, dataLen = %{public}u", sessionId, dataLen);
}

static void OnMessageReceived_recv(int sessionId, const void* data, unsigned int dataLen)
{
    LOGI("OnMessageReceived,sesison id = %{public}d, dataLen = %{public}u", sessionId, dataLen);

    char networkId[DEVICE_ID_SIZE_MAX];
    int ret = ::GetPeerDeviceId(sessionId, networkId, DEVICE_ID_SIZE_MAX);
    if (ret != SOFTBUS_OK) {
        LOGE("GetPeerDeviceId failed, error = %{public}d", ret);
        ::SendMessage(sessionId, SYNC_SEND_TASK_FAIL.data(), SYNC_SEND_TASK_FAIL.size());
        return;
    }

    std::string jsonStr((const char *)data, dataLen);
    LOGI("%{public}s", jsonStr.c_str());
    nlohmann::json jsonObject = nlohmann::json::parse(jsonStr, nullptr, false);
    if (jsonObject.is_discarded()) {
        LOGE("json parse failed");
        ::SendMessage(sessionId, SYNC_SEND_TASK_FAIL.data(), SYNC_SEND_TASK_FAIL.size());
        return;
    }

    SendTask task;
    JsonToSendTask(jsonObject, task);
    if (task.networkId != networkId) {
        LOGE("networkId not match");
        ::SendMessage(sessionId, SYNC_SEND_TASK_FAIL.data(), SYNC_SEND_TASK_FAIL.size());
        return;
    }
    if (!SendManager::GetInstance().AddSinkSessionInfo(task.deviceId, task)) {
        LOGE("AddSinkSessionInfo failed");
        ::SendMessage(sessionId, SYNC_SEND_TASK_FAIL.data(), SYNC_SEND_TASK_FAIL.size());
        return;
    }
    ::SendMessage(sessionId, SYNC_SEND_TASK_SUCCESS.data(), SYNC_SEND_TASK_SUCCESS.size());
}

static int OnReceiveFileStarted(int sessionId, const char *files, int fileCnt)
{
    LOGI("File receive start sessionId = %{public}d, first file = %{public}s, fileCnt = %{public}d", sessionId, files, fileCnt);
    SendManager::GetInstance().NotifyEvent(sessionId, SendType::SINK, SendState::PROCESSING);
    g_sendState = SendState::PROCESSING;
    gettimeofday(&recv_start_time, nullptr);
    lastBytesUpload_recv = 0;
    return 0;
}

static int OnReceiveFileProcess(int sessionId, const char *firstFile, uint64_t bytesUpload, uint64_t bytesTotal)
{
    LOGI("OnReceiveFileProcess sessionId = %{public}d, bytesUpload = %{public}llu, total = %{public}llu", sessionId, bytesUpload, bytesTotal);
    int progress = int((double)bytesUpload / (double)bytesTotal * DEC_TO_PERCENT);
    gettimeofday(&recv_end_time, nullptr);
    double costs = ((double)(recv_end_time.tv_sec - recv_start_time.tv_sec) * S_TO_MS + (double)(recv_end_time.tv_usec - recv_start_time.tv_usec) / S_TO_MS); // ms
    int speed = (int)(((double)bytesUpload - (double)lastBytesUpload_recv) / 1024 / costs * S_TO_MS); // KB/s
    SendManager::GetInstance().NotifyEvent(sessionId, SendType::SINK, SendState::PROCESSING, speed, progress);
    g_sendState = SendState::PROCESSING;
    gettimeofday(&recv_start_time, nullptr);
    lastBytesUpload_recv = bytesUpload;
    return 0;
}

static void OnReceiveFileFinished(int sessionId, const char *files, int fileCnt)
{
    LOGI("File receive finished sessionId = %{public}d, first file = %{public}s, fileCnt = %{public}d", sessionId, files, fileCnt);
    bool success = true;
    LOGI("Check recv file hash %{public}s", success ? "ok" : "error");
    if (success) {
        success = SendManager::GetInstance().HandleMediaAsset(sessionId);
        LOGI("Handle media asset %{public}s", success ? "ok" : "error");
    }
    g_recvFlag.store(true, std::memory_order_relaxed);
    if (success) {
        SendManager::GetInstance().NotifyEvent(sessionId, SendType::SINK, SendState::SUCCESS, 0 , 100);
        g_sendState = SendState::SUCCESS;
    } else {
        SendManager::GetInstance().NotifyEvent(sessionId, SendType::SINK, SendState::FAILURE);
        g_sendState = SendState::FAILURE;
    }
    lastBytesUpload_recv = 0;
}

static void OnFileTransError_recv(int sessionId)
{
    LOGI("OnFileTransError sessionId = %{public}d", sessionId);
    SendManager::GetInstance().NotifyEvent(sessionId, SendType::SINK, SendState::FAILURE);
    g_sendState = SendState::FAILURE;
    lastBytesUpload_recv = 0;
}

// send callback
static int OnSessionOpened_send(int sessionId, int result)
{
    int dataType = TYPE_BUTT;
    GetSessionOption(sessionId, SESSION_OPTION_DATA_TYPE, &dataType, sizeof(uint32_t));
    LOGI("session opened, sesison id = %{public}d, result = %{public}d, dataType = %{public}d", sessionId, result, dataType);
    if (result == SOFTBUS_OK) {
        if (dataType == TYPE_MESSAGE) {
            std::unique_lock<std::mutex> lock(g_syncMutex);
            g_syncResult = SYNC_SEND_TASK_SUCCESS;
            g_syncCondition.notify_all();
        } else if (dataType == TYPE_FILE) {
            g_openFlag_send.store(true, std::memory_order_relaxed);
            SendManager::GetInstance().NotifyEvent(sessionId, SendType::SRC, SendState::UNKNOWN);
            g_sendState = SendState::UNKNOWN;
        }
    }
    return result;
}

static void OnSessionClosed_send(int sessionId)
{
    int dataType = TYPE_BUTT;
    GetSessionOption(sessionId, SESSION_OPTION_DATA_TYPE, &dataType, sizeof(uint32_t));
    LOGI("session closed, session id = %{public}d, dataType = %{public}d", sessionId, dataType);
    if (dataType == TYPE_FILE) {
        g_openFlag_send.store(false, std::memory_order_relaxed);
        if (g_sendState == SendState::PROCESSING) {
            LOGI("remote device abort send file.");
            SendManager::GetInstance().NotifyEvent(sessionId, SendType::SINK, SendState::ABORT, 0 , 0);
            g_sendState = SendState::ABORT;
        }
        SendManager::GetInstance().SetSendStopFlag(sessionId);
    }
}

static void OnBytesReceived_send(int sessionId, const void* data, unsigned int dataLen)
{
   LOGI("DataBytesReceived, sesison id = %{public}d, dataLen = %{public}d", sessionId, dataLen);
}

static void OnMessageReceived_send(int sessionId, const void* data, unsigned int dataLen)
{
    LOGI("OnMessageReceived, sesison id = %{public}d, dataLen = %{public}d", sessionId, dataLen);

    std::unique_lock<std::mutex> lock(g_syncMutex);
    g_syncResult = std::string((const char *)data, dataLen);
    g_syncCondition.notify_all();
}

static int OnSendFileProcess(int sessionId, uint64_t bytesUpload, uint64_t bytesTotal)
{
    LOGI("OnSendFileProcess sessionId = %{public}d, bytesUpload = %{public}llu, total = %{public}llu", sessionId, bytesUpload, bytesTotal);
    int progress = int((double)bytesUpload / (double)bytesTotal * DEC_TO_PERCENT);
    gettimeofday(&send_end_time, nullptr);
    double costs = ((double)(send_end_time.tv_sec - send_start_time.tv_sec) * S_TO_MS + (double)(send_end_time.tv_usec - send_start_time.tv_usec) / S_TO_MS); // ms
    int speed = (int)(((double)bytesUpload - (double)lastBytesUpload_send) / 1024 / costs * S_TO_MS); // KB/s
    SendManager::GetInstance().NotifyEvent(sessionId, SendType::SRC, SendState::PROCESSING, speed, progress);
    g_sendState = SendState::PROCESSING;
    gettimeofday(&send_start_time, nullptr);
    lastBytesUpload_send = bytesUpload;
    return 0;
}

static int OnSendFileFinished(int sessionId, const char *firstFile)
{
    LOGI("OnSendFileFinished sessionId = %{public}d, first file = %{public}s", sessionId, firstFile);
    SendManager::GetInstance().NotifyEvent(sessionId, SendType::SRC, SendState::SUCCESS, 0 , 100);
    g_sendState = SendState::SUCCESS;
    SendManager::GetInstance().SetSendStopFlag(sessionId);
    lastBytesUpload_send = 0;
    ::CloseSession(sessionId);
    return 0;
}

static void OnFileTransError_send(int sessionId)
{
    LOGI("OnFileTransError sessionId = %{public}d", sessionId);
    SendManager::GetInstance().NotifyEvent(sessionId, SendType::SRC, SendState::FAILURE);
    g_sendState = SendState::FAILURE;
    ::CloseSession(sessionId);
    SendManager::GetInstance().SetSendStopFlag(sessionId);
    lastBytesUpload_send = 0;
}

static ISessionListener sessionlistener_recv = {
    .OnSessionOpened = OnSessionOpened_recv,
    .OnSessionClosed = OnSessionClosed_recv,
    .OnBytesReceived = OnBytesReceived_recv,
    .OnMessageReceived = OnMessageReceived_recv,
};

static IFileReceiveListener fileRecvListener = {
    .OnRenameFile = OnRenameFile,
    .OnReceiveFileStarted = OnReceiveFileStarted,
    .OnReceiveFileProcess = OnReceiveFileProcess,
    .OnReceiveFileFinished = OnReceiveFileFinished,
    .OnFileTransError = OnFileTransError_recv,
};

static ISessionListener sessionlistener_send = {
    .OnSessionOpened = OnSessionOpened_send,
    .OnSessionClosed = OnSessionClosed_send,
    .OnBytesReceived = OnBytesReceived_send,
    .OnMessageReceived = OnMessageReceived_send,
};

static IFileSendListener fileSendListener = {
    .OnSendFileProcess = OnSendFileProcess,
    .OnSendFileFinished = OnSendFileFinished,
    .OnFileTransError = OnFileTransError_send,
};

int32_t SendManager::CreateSession()
{
    LOGI("CreateSession start.");

    int32_t ret = CreateSessionServer(SESSION_PKG_NAME, SESSION_NAME_SERVICE, &sessionlistener_recv);
    if (ret != FS_SUCCESS) {
        LOGE("server session create failed. ret = %{public}d.", ret);
        return FS_CREATE_SESSION_SERVER_FAILED;
    }

    ret = CreateSessionServer(SESSION_PKG_NAME, SESSION_NAME_CLIENT, &sessionlistener_send);
    if (ret != FS_SUCCESS) {
        LOGE("session create failed. ret = %{public}d.", ret);
        return FS_CREATE_SESSION_SERVER_FAILED;
    }

    ret = SetFileSendListener(SESSION_PKG_NAME, SESSION_NAME_CLIENT, &fileSendListener);
    if (ret != FS_SUCCESS) {
        LOGE("file send listener set failed. ret = %{public}d.", ret);
        return FS_CREATE_SESSION_SERVER_FAILED;
    }

    LOGI("CreateSession end.");
    return FS_SUCCESS;
}
int32_t SendManager::Init()
{
    LOGI("SendManager Init.");
    int32_t ret = CreateSession();
    if (ret != FS_SUCCESS) {
        LOGE("CreateSession failed.");
        return ret;
    }

    sendQueue_ = std::make_shared<FileShareQueue<SendTask>>();
    if (sendQueue_ == nullptr) {
        LOGE("SendQueue create failed.");
        return FS_OUT_OF_MEMORY;
    }

    processThr_ = std::thread(&SendManager::ProcessThread, this);
    isStop_ = false;

    int retryTimes = 0;
    auto initCallback = std::make_shared<DeviceInitCallBack>();
    while (retryTimes++ < GET_DEVICE_RETRY_TIMES) {
        ret = DistributedHardware::DeviceManager::GetInstance().InitDeviceManager(PKG_NAME, initCallback);
        if (ret == FS_SUCCESS) {
            break;
        }
        LOGI("InitDeviceManager, waiting for:%{public}d ms.", retryTimes * SEARCH_RETRY_INTERVAL_MS);
        std::this_thread::sleep_for(std::chrono::milliseconds(SEARCH_RETRY_INTERVAL_MS));
    }

    if (ret != FS_SUCCESS) {
        LOGE("InitDeviceManager failed.");
        return FS_INIT_DEV_MANAGER_FAILED;
    }
    LOGI("InitDeviceManager success.");
    MimeTypeUtils::InitMimeTypeMap();

    return FS_SUCCESS;
}

int32_t SendManager::DeInit()
{
    LOGI("SendManager DeInit.");
    int ret = RemoveSessionServer(SESSION_PKG_NAME, SESSION_NAME_SERVICE);
    if (ret != FS_SUCCESS) {
        LOGE("RemoveSessionServer service failed. ret = %{public}d.", ret);
        return FS_REMOVE_SESSION_SERVER_FAILED;
    }
    ret = RemoveSessionServer(SESSION_PKG_NAME, SESSION_NAME_CLIENT);
    if (ret != FS_SUCCESS) {
        LOGE("RemoveSessionServer client failed. ret = %{public}d.", ret);
        return FS_REMOVE_SESSION_SERVER_FAILED;
    }

    isStop_ = true;
    if (sendQueue_ != nullptr) {
        sendQueue_->Stop();
        sendQueue_->Clear();
    }
    callback_ = nullptr;
    sessionInfoMap_send_.clear();
    sessionInfoMap_recv_.clear();
    return FS_SUCCESS;
}

int32_t SendManager::SendFile(SendTask &task)
{
    LOGI("SendManager::SendFile start.");
    if (task.deviceId.empty() || task.files.empty()) {
        LOGE("SendFile failed, deviceId or fileInfo is empty.");
        return FS_INVALID_PARAM;
    }
    if (task.type == ShareType::SAVE_AS_FOLDER && task.folderName.empty()) {
        LOGE("SendFile failed, folder name is empty.");
        return FS_INVALID_PARAM;
    }

    int32_t ret = CheckFilePaths(task.files);
    if (ret != FS_SUCCESS) {
        LOGE("CheckFilePaths failed.");
        return ret;
    }

    ret = GetNetWorkId(task);
    if (ret != FS_SUCCESS) {
        LOGE("GetNetworkId failed.");
        return ret;
    }

    ret = sendQueue_->Push(task, true);
    if (ret != FS_SUCCESS) {
        LOGE("send queue push failed.");
        return ret;
    }

    return FS_SUCCESS;
}

int32_t SendManager::RegisterFileShareCallback(sptr<IFileShareCallback> callback)
{
    LOGI("SendManager::RegisterFileShareCallback start.");
    CHKPTR(callback, FS_NULL_PARAM);
    callback_ = callback;
    return FS_SUCCESS;
}

int32_t SendManager::UnRegisterFileShareCallback()
{
    LOGI("SendManager::UnRegisterFileShareCallback start.");
    callback_ = nullptr;
    return FS_SUCCESS;
}

int32_t SendManager::CheckFilePaths(std::vector<FileInfo> &files)
{
    if (files.empty()) {
        LOGE("files is empty.");
        return FS_NULL_PARAM;
    }

    for (auto &file : files) {
        char realPath[PATH_MAX];
        if (realpath(file.path.c_str(), realPath) == nullptr) {
            LOGE("file: %{public}s not exist.", file.path.c_str());
            return FS_INVALID_PARAM;
        }

        struct stat fileStat;
        if (stat(realPath, &fileStat) != 0) {
            LOGE("Open file: %{public}s failed.", realPath);
            return FS_INVALID_PARAM;
        }

        if (!S_ISREG(fileStat.st_mode)) {
            LOGE("%{public}s is not a file.", realPath);
            return FS_INVALID_PARAM;
        }

        file.origFileName = ExtractFileName(file.path);
    }

    return FS_SUCCESS;
}

int32_t SendManager::HashFile(std::vector<FileInfo> &files)
{
    if (files.empty()) {
        LOGE("files is empty.");
        return FS_NULL_PARAM;
    }

    int ret = 0;
    for (auto&& file : files) {
        std::tie(ret, file.hash) = FileHash::HashWithMD5(file.path);
        if (ret != 0) {
            LOGE("%{public}s hash file failed, errno %{public}d", file.path.c_str(), ret);
            return FS_HASH_FAILED;
        }
    }
    return FS_SUCCESS;
}

int32_t SendManager::GetNetWorkId(SendTask &task)
{
    std::vector<DistributedHardware::DmDeviceInfo> dmDeviceInfoList;
    int retryTimes = 0;
    while (retryTimes++ < GET_DEVICE_RETRY_TIMES) {
        int32_t ret = DistributedHardware::DeviceManager::GetInstance().GetTrustedDeviceList(PKG_NAME, "", dmDeviceInfoList);
        if (!dmDeviceInfoList.empty() && ret == FS_SUCCESS) {
            break;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(SEARCH_RETRY_INTERVAL_MS));
    }

    if (dmDeviceInfoList.empty()) {
        LOGE("GetTrustedDeviceList failed, dmDeviceInfoList is empty.");
        return FS_GET_TRUST_DEVICE_INFO_FAILED;
    }

    // Only 1 to 1 file sharing are considered
    task.networkId = std::string(dmDeviceInfoList[0].networkId);
    task.deviceName = std::string(dmDeviceInfoList[0].deviceName);
    LOGI("GetNetWorkId success.");
    return FS_SUCCESS;
}

void SendManager::ProcessThread()
{
    while (!isStop_) {
        SendTask task {};
        int ret = sendQueue_->Pop(task);
        if (ret == FS_QUEUE_STOPED) {
            LOGI("send queue stoped.");
            break;
        } else if (ret != FS_SUCCESS) {
            LOGE("send queue pop failed.");
            continue;
        }
        
        ret = OpenSessionAndSendFile(task);
        if (ret != FS_SUCCESS) {
            LOGE("OpenSessionAndSendFile failed.");
            NotifyEventInner(SendState::FAILURE, task.type);
            continue;
        }
    }
}

void SendManager::UpdateFileInfo(int sessionId, const char *storagePath, const char *fileName, const char *newFileName)
{
    auto it = std::find_if(sessionInfoMap_recv_.begin(), sessionInfoMap_recv_.end(),
        [sessionId](const std::pair<std::string, SessionInfo> &item) { return sessionId == item.second.sessionId; });
    if (it == sessionInfoMap_recv_.end()) {
        LOGE("can't find sessionId");
        return;
    }

    auto &files = it->second.files;
    auto iter = std::find_if(files.begin(), files.end(),
        [fileName](const FileInfo &file) { return file.origFileName == fileName; });
    if (iter != files.end()) {
        iter->newFileName = newFileName;
        iter->recvPath = IncludeTrailingPathDelimiter(storagePath) + newFileName;
    } else {
        LOGE("update file info error, fileName = %{public}s", fileName);
    }
}

bool SendManager::CheckFileHash(int sessionId)
{
    auto it = std::find_if(sessionInfoMap_recv_.begin(), sessionInfoMap_recv_.end(),
        [sessionId](const std::pair<std::string, SessionInfo> &item) { return sessionId == item.second.sessionId; });
    if (it == sessionInfoMap_recv_.end()) {
        LOGE("can't find sessionId");
        return false;
    }

    auto &files = it->second.files;
    std::string filePath = "";
    for (const auto &file : files) {
        auto [ret, hash] = FileHash::HashWithMD5(file.recvPath);
        if (ret != 0) {
            LOGE("%{public}s hash file failed, errno %{public}d", file.recvPath.c_str(), ret);
            filePath = file.recvPath;
            break;
        }
        if (hash != file.hash) {
            LOGE("hash match failed, origFileName = %{public}s, newFileName = %{public}s",
                file.origFileName.c_str(), file.newFileName.c_str());
            filePath = file.recvPath;
            break;
        }
    }
    if (!filePath.empty()) {
        if (it->second.type == ShareType::SAVE_AS_FOLDER) {
            ForceRemoveDirectory(ExtractFilePath(filePath));
        } else {
            for (const auto &file : files) {
                RemoveFile(file.recvPath);
            }
        }
        return false;
    }
    return true;
}

bool SendManager::ReadySinkSession(const std::string &networkId, int sessionId)
{
    auto it = std::find_if(sessionInfoMap_recv_.begin(), sessionInfoMap_recv_.end(),
        [&networkId](const std::pair<std::string, SessionInfo> &item) { return networkId == item.second.networkId; });
    if (it == sessionInfoMap_recv_.end()) {
        LOGE("can't find networkId");
        return false;
    }

    it->second.sessionId = sessionId;
    return true;
}

bool SendManager::AddSinkSessionInfo(const std::string &deviceId, SendTask &task)
{
    SessionInfo sessionInfo = {
        .networkId = task.networkId,
        .type = task.type,
        .files = task.files,
    };
    sessionInfoMap_recv_[deviceId] = sessionInfo;

    std::string storagePath = GetSinkStoragePath();
    if (task.type == ShareType::SAVE_AS_FOLDER) {
        std::string name = Rename(storagePath, task.folderName, false);
        storagePath = OHOS::IncludeTrailingPathDelimiter(storagePath) + name;
        if (mkdir(storagePath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
            LOGE("CreateDir:%{pulbic}s error", storagePath.c_str());
            return false;
        }
    }
    int ret = SetFileReceiveListener(SESSION_PKG_NAME, SESSION_NAME_SERVICE, &fileRecvListener, storagePath.c_str());
    if (ret != FS_SUCCESS) {
        LOGE("file recv listener set failed. ret = %{public}d.", ret);
        return false;
    }
    return true;
}

void SendManager::RemoveSinkSessionInfo(int sessionId)
{
    auto it = std::find_if(sessionInfoMap_recv_.begin(), sessionInfoMap_recv_.end(),
        [sessionId](const std::pair<std::string, SessionInfo> &item) { return sessionId == item.second.sessionId; });
    if (it != sessionInfoMap_recv_.end()) {
        sessionInfoMap_recv_.erase(it);
    }
}

int32_t SendManager::SyncSendTask(SendTask task)
{
    DistributedHardware::DmDeviceInfo localDeviceInfo;
    if (DistributedHardware::DeviceManager::GetInstance().GetLocalDeviceInfo(PKG_NAME, localDeviceInfo) != FS_SUCCESS) {
        LOGE("GetLocalDeviceInfo failed.");
        return FS_INVALID_PARAM;
    }

    // 由于TYPE_FILE只能传递文件，这里只能创建TYPE_MESSAGE来同步消息
    SessionAttribute sessionAttr = {
        .dataType = TYPE_MESSAGE,
        .linkTypeNum = 2,
        .linkType[0] = LINK_TYPE_WIFI_P2P,
        .linkType[1] = LINK_TYPE_WIFI_WLAN_5G,
    };
    int sessionId = ::OpenSession(SESSION_NAME_CLIENT, SESSION_NAME_SERVICE, task.networkId.c_str(), GROUP_ID, &sessionAttr);
    LOGI("send message sessionId = %{public}d.", sessionId);
    {
        std::unique_lock<std::mutex> lock(g_syncMutex);
        g_syncResult.clear();
        if (!g_syncCondition.wait_for(lock,
            std::chrono::milliseconds(OPEN_SESSION_RETRY_TIMES * OPEN_SESSION_RETRY_INTERVAL_MS),
            [] { return !g_syncResult.empty(); })) {
            LOGE("OpenSession timeout.");
            return FS_OPEN_SESSION_TIME_OUT;
        }
    }

    task.networkId = localDeviceInfo.networkId;
    task.deviceId = localDeviceInfo.deviceId;
    task.deviceName = localDeviceInfo.deviceName;
    nlohmann::json jsonObject;
    SendTaskToJson(task, jsonObject);
    std::string message = jsonObject.dump();
    int ret = ::SendMessage(sessionId, message.data(), message.size());
    if (ret != SOFTBUS_OK) {
        LOGE("SendMessage failed, error %{public}d", ret);
        ::CloseSession(sessionId);
        return FS_SEND_MESSAGE_FAILED;
    }

    {
        std::unique_lock<std::mutex> lock(g_syncMutex);
        g_syncResult.clear();
        if (!g_syncCondition.wait_for(lock,
            std::chrono::milliseconds(OPEN_SESSION_RETRY_TIMES * OPEN_SESSION_RETRY_INTERVAL_MS),
            [] { return !g_syncResult.empty(); })) {
            LOGE("SendMessage timeout.");
            ::CloseSession(sessionId);
            return FS_SEND_MESSAGE_FAILED;
        }
    }

    ::CloseSession(sessionId);
    return g_syncResult == SYNC_SEND_TASK_SUCCESS ? FS_SUCCESS : FS_SEND_FILE_FAILED;
}

int32_t SendManager::OpenSessionAndSendFile(SendTask &task)
{
    if (task.networkId.empty()) {
        LOGE("OpenSessionAndSendFile failed, networkId is empty.");
        return FS_INVALID_PARAM;
    }

    int ret = SyncSendTask(task);
    if (ret != FS_SUCCESS) {
        LOGE("SyncSendTask failed");
        return ret;
    }

    std::vector<const char *> sourceFileList;
    for (auto&& file : task.files) {
        sourceFileList.push_back(file.path.data());
    }

    g_openFlag_send.store(false, std::memory_order_relaxed);
    // OpenSession
    static SessionAttribute sessionAttr = {
        .dataType = TYPE_FILE,
        .linkTypeNum = 2,
        .linkType[0] = LINK_TYPE_WIFI_P2P,
        .linkType[1] = LINK_TYPE_WIFI_WLAN_5G,
    };

    int sessionId = ::OpenSession(SESSION_NAME_CLIENT, SESSION_NAME_SERVICE, task.networkId.c_str(), GROUP_ID, &sessionAttr);
    
    SessionInfo sessionInfo = {
        .sessionId = sessionId,
        .networkId = task.networkId,
        .sendFlag = true,
        .type = task.type,
        .files = task.files,
    };
    sessionInfoMap_send_[task.deviceId] = sessionInfo;

    int retryTimes = 0;
    while ((g_openFlag_send.load(std::memory_order_acquire) == false) && (retryTimes++ < OPEN_SESSION_RETRY_TIMES)) {
        std::this_thread::sleep_for(std::chrono::milliseconds(OPEN_SESSION_RETRY_INTERVAL_MS));
        if (retryTimes % LOG_SPAN == 0) {
            LOGI("openSession, waiting for:%{public}d ms", retryTimes * OPEN_SESSION_RETRY_INTERVAL_MS);
        }
    }

    if (retryTimes == OPEN_SESSION_RETRY_TIMES) {
        LOGE("open session timeout.");
        sessionInfoMap_send_[task.deviceId].sendFlag = false;
        return FS_OPEN_SESSION_TIME_OUT;
    }
    LOGI("open session sessionId = %{public}d\n", sessionId);

    ret = ::SendFile(sessionId, sourceFileList.data(), nullptr, sourceFileList.size());
    if (ret != FS_SUCCESS) {
        ::CloseSession(sessionId);
        sessionInfoMap_send_[task.deviceId].sendFlag = false;
        LOGE("send file result = %{public}d, sessionId = %{public}d", ret, sessionId);
        return FS_SEND_FILE_FAILED;
    }
    gettimeofday(&send_start_time, nullptr);
    return FS_SUCCESS;
}

void SendManager::NotifyEvent(int sessionId, SendType type, SendState state, int speed, int progress)
{
    if (callback_ == nullptr) {
        LOGE("OnSendEvent failed. callback function is nullptr.");
        return;
    }
    SendInfo sendInfo;
    sendInfo.progress = progress;
    sendInfo.speed = speed;
    if (type == SendType::SRC) {
        std::string deviceId = GetDeviceId(sessionId);
        sendInfo.type = sessionInfoMap_send_[deviceId].type;
    }

    int32_t ret = callback_->OnSendEvent(state, sendInfo);
    if (ret != FS_SUCCESS) {
        LOGE("OnSendEvent failed. ret = %{public}d.", ret);
    }
}

std::string SendManager::GetDeviceId(int sessionId)
{
    int retryTimes = 0;
    while (retryTimes++ < GET_NAME_RETRY_TIMES) {
        for (auto it = sessionInfoMap_send_.begin(); it != sessionInfoMap_send_.end(); ++it) {
            if (it->second.sessionId == sessionId) {
                return it->first;
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(SEARCH_RETRY_INTERVAL_MS));
    }
    return "";
}

void SendManager::SetSendStopFlag(int sessionId)
{
    LOGD("SetSendStopFlag sessionId = %{public}d.", sessionId);
    std::string deviceId = GetDeviceId(sessionId);
    if (sessionInfoMap_send_.find(deviceId) != sessionInfoMap_send_.end()) {
        LOGI("SetSendStopFlag deviceId = %{public}s.", deviceId.c_str());
        sessionInfoMap_send_[deviceId].sendFlag = false;
        sessionInfoMap_send_[deviceId].sessionId = -1;
    }
}

int32_t SendManager::CancelSendFile(const std::string &deviceId)
{
    if (deviceId.empty()) {
        LOGE("CancelSendFile failed, deviceId is empty.");
        return FS_INVALID_PARAM;
    }

    if (sessionInfoMap_send_.find(deviceId) == sessionInfoMap_send_.end()) {
        LOGE("CancelSendFile failed, deviceId is not found.");
        return FS_INVALID_PARAM;
    }

    ::CloseSession(sessionInfoMap_send_[deviceId].sessionId);
    sessionInfoMap_send_[deviceId].sendFlag = false;
    sessionInfoMap_send_[deviceId].sessionId = -1;

    CHKPTR(callback_, FS_NULL_PARAM);
    SendState state = SendState::CANCEL;
    SendInfo sendInfo {};
    int32_t ret = callback_->OnSendEvent(state, sendInfo);
    if (ret != FS_SUCCESS) {
        LOGE("OnSendEvent failed. ret = %{public}d.", ret);
        return ret;
    }

    return FS_SUCCESS;
}

int32_t SendManager::AbortReceiveFile(const std::string &deviceId)
{
    std::vector<DistributedHardware::DmDeviceInfo> dmDeviceInfoList;
    int32_t ret = DistributedHardware::DeviceManager::GetInstance().GetTrustedDeviceList(PKG_NAME, "", dmDeviceInfoList);
    if (ret != FS_SUCCESS) {
        LOGE("GetTrustedDeviceList failed");
        return FS_ABORT_RECV_FAILED;
    }
    std::string networkId = std::string(dmDeviceInfoList[0].networkId);

    auto it = std::find_if(sessionInfoMap_recv_.begin(), sessionInfoMap_recv_.end(),
        [&networkId](const std::pair<std::string, SessionInfo> &item) { return networkId == item.second.networkId; });
    if (it == sessionInfoMap_recv_.end()) {
        LOGE("AbortReceiveFile failed, can't find networkId");
        return FS_ABORT_RECV_FAILED;
    }

    ::CloseSession(it->second.sessionId);

    CHKPTR(callback_, FS_NULL_PARAM);
    SendState state = SendState::ABORT;
    SendInfo sendInfo {};
    ret = callback_->OnSendEvent(state, sendInfo);
    if (ret != FS_SUCCESS) {
        LOGE("OnSendEvent failed. ret = %{public}d.", ret);
        return ret;
    }
    return FS_SUCCESS;
}

int32_t SendManager::SetShareStatus(const bool status)
{
    std::lock_guard<std::mutex> shareStatusLock(shareStatusMutex_);
    shareStatus_ = status;

    for (auto it = shareStatusCallbackMap_.begin(); it != shareStatusCallbackMap_.end(); ++it) {
        int32_t ret = it->second->OnShareStatusEvent(shareStatus_);
        if (ret != FS_SUCCESS) {
            LOGE("OnShareStatusEvent failed. ret = %{public}d.", ret);
        }
    }
    
    if(!isRegister_){
        std::function<void(void)> func = [this](){
            int32_t ret = ChangeUuid(ORIGIN_UUID);
            if (ret != FS_SUCCESS) {
                return;
            }
            ret = DistributedHardware::DeviceManager::GetInstance().UnPublishDeviceDiscovery(PKG_NAME, PUBLISH_ID);
            if (ret != FS_SUCCESS) {
                LOGE("%{public}s UnPublishDeviceDiscovery failed, ret %{public}d", PKG_NAME.c_str(), ret);
                return;
            }
            for (auto it = this->shareStatusCallbackMap_.begin(); it != this->shareStatusCallbackMap_.end(); ++it) {
                int32_t ret = it->second->OnShareStatusEvent(false);
                LOGI("OnShareStatusEvent");
                if (ret != FS_SUCCESS) {
                    LOGE("OnShareStatusEvent failed. ret = %{public}d.", ret);
                }
            }
            this->shareStatus_ = false;
        };
        FileShareConfig::GetInstance().RegisterCallback(func);
        isRegister_ = true;
    }

    if(FileShareConfig::GetInstance().GetWorkDuration() == 0){
        return FS_SUCCESS;
    }           

    if(shareStatus_){
        FileShareConfig::GetInstance().StartTimer();
    }else{
        FileShareConfig::GetInstance().StopTimer();
    }

    return FS_SUCCESS;
}

int32_t SendManager::GetShareStatus(bool &status)
{
    std::lock_guard<std::mutex> shareStatusLock(shareStatusMutex_);
    status =  shareStatus_;

    return FS_SUCCESS;
}
int32_t SendManager::RegisterShareStatusCallback(const std::string &bundleName, const sptr<IFileShareCallback> &callback)
{
    LOGI("SendManager::RegisterShareStatusCallback start.");

    if (bundleName.empty()) {
        LOGE("RegisterShareStatusCallback failed, bundleName is empty.");
        return FS_INVALID_PARAM;
    }
    
    CHKPTR(callback, FS_NULL_PARAM);
    shareStatusCallbackMap_[bundleName] = callback;

    return FS_SUCCESS;
}
int32_t SendManager::UnRegisterShareStatusCallback(const std::string &bundleName)
{
    LOGI("SendManager::UnRegisterShareStatusCallback start.");

    if (bundleName.empty()) {
        LOGE("RegisterShareStatusCallback failed, bundleName is empty.");
        return FS_INVALID_PARAM;
    }

    if (shareStatusCallbackMap_.find(bundleName) == shareStatusCallbackMap_.end()) {
        LOGE("UnRegisterShareStatusCallback failed, bundleName is not found.");
        return FS_INVALID_PARAM;
    }

    shareStatusCallbackMap_[bundleName] = nullptr;
    shareStatusCallbackMap_.erase(bundleName);

    return FS_SUCCESS;
}

int32_t SendManager::ChangeUuid(const uint16_t uuid)
{
    if (uuid == 0) {
        LOGE("ChangeUuid failed, uuid is 0.");
        return FS_INVALID_PARAM;
    }

    int32_t ret = ::SetBleUuidLNN(uuid);
    if (ret != FS_SUCCESS) {
        LOGE("SetBleUuidLNN failed. ret = %{public}d.", ret);
        return FS_SET_BLE_UUID_LNN_FAILED;
    }

    return FS_SUCCESS;
}

void SendManager::NotifyEventInner(SendState state, ShareType type)
{
    if (callback_ == nullptr) {
        LOGE("OnSendEvent failed. callback function is nullptr.");
        return;
    }

    SendInfo sendInfo;
    sendInfo.type = type;

    int32_t ret = callback_->OnSendEvent(state, sendInfo);
    if (ret != FS_SUCCESS) {
        LOGE("OnSendEvent failed. ret = %{public}d.", ret);
    }    
}

bool SendManager::HandleMediaAsset(int sessionId)
{
    auto it = std::find_if(sessionInfoMap_recv_.begin(), sessionInfoMap_recv_.end(),
        [sessionId](const std::pair<std::string, SessionInfo> &item) { return sessionId == item.second.sessionId; });
    if (it == sessionInfoMap_recv_.end()) {
        LOGE("can't find sessionId");
        return false;
    }

    if (it->second.type != ShareType::SAVE_TO_MEDIA_ASSET) {
        LOGI("ShareType is %{public}d, skip handle media asset", it->second.type);
        return true;
    }

    auto &files = it->second.files;
    std::function<void()> RemoveFiles = [&files]() {
        for (const auto &file : files) {
            RemoveFile(file.recvPath);
        }
    };

    uint64_t tokenId = GetSelfTokenID();
    if (!TokenIdKit::IsSystemAppByFullTokenID(tokenId)) {
        SetSelfTokenID(tokenId | SYSTEM_APP_MASK);
        AccessTokenKit::ReloadNativeTokenInfo();
    }
    tokenId = GetSelfTokenID();
    if (!TokenIdKit::IsSystemAppByFullTokenID(tokenId)) {
        LOGE("set file_share_service to system app failed");
        RemoveFiles();
        return false;
    }

    if (!UserFileClient::IsValid()) {
        auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
        if (saManager != nullptr) {
            auto remoteObj = saManager->GetSystemAbility(FILE_SHARE_SERVICE_ID);
            if (remoteObj != nullptr) {
                UserFileClient::Init(remoteObj, true);
            }
        }
    }
    if (!UserFileClient::IsValid()) {
        LOGE("UserFileClient creation failed");
        RemoveFiles();
        return false;
    }

    std::string uri = UFM_QUERY_PHOTO_ALBUM;
    MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
    Uri queryShareAlbumUri(uri);
    std::vector<DataShare::OperationItem> operations;
    operations.push_back({ DataShare::EQUAL_TO, { PhotoAlbumColumns::ALBUM_NAME, MEDIA_SHARE_ALBUM_NAME } });
    DataShare::DataSharePredicates queryPredicates(operations);
    queryPredicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, std::to_string(PhotoAlbumType::USER));
    queryPredicates.And()->EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, std::to_string(PhotoAlbumSubType::USER_GENERIC));
    std::vector<std::string> fetchColumn = { PhotoAlbumColumns::ALBUM_ID };
    int errCode = 0;
    int albumId = -1;
    auto resultSet = UserFileClient::Query(queryShareAlbumUri, queryPredicates, fetchColumn, errCode);
    if (resultSet != nullptr && resultSet->GoToFirstRow() == NativeRdb::E_OK) {
        int index = 0;
        if (resultSet->GetColumnIndex(PhotoAlbumColumns::ALBUM_ID, index) == NativeRdb::E_OK) {
            resultSet->GetInt(index, albumId);
        }
    }
    if (albumId < 0) {
        uri = UFM_CREATE_PHOTO_ALBUM;
        MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
        Uri createShareAlbumUri(uri);
        DataShare::DataShareValuesBucket valuesBucket;
        valuesBucket.Put(PhotoAlbumColumns::ALBUM_NAME, MEDIA_SHARE_ALBUM_NAME);
        valuesBucket.Put(PhotoAlbumColumns::ALBUM_IS_LOCAL, 1);
        albumId = UserFileClient::Insert(createShareAlbumUri, valuesBucket);
    }
    if (albumId < 0) {
        LOGE("failed to create share album");
        RemoveFiles();
        return false;
    }
    LOGI("share album id is %{public}d", albumId);

    std::vector<std::string> fileUris;
    for (const auto &file : files) {
        if (!CopyFileToMediaAsset(file, fileUris)) {
            LOGE("copy file to album failed");
            RemoveFiles();
            return false;
        }
    }

    std::vector<DataShare::DataShareValuesBucket> valuesBuckets;
    for (const auto &fileUri : fileUris) {
        DataShare::DataShareValuesBucket valuesBucket;
        valuesBucket.Put("map_album", albumId);
        valuesBucket.Put("map_asset", fileUri);
        valuesBuckets.push_back(valuesBucket);
    }
    Uri addAssetUri(UFM_PHOTO_ALBUM_ADD_ASSET);
    if (UserFileClient::BatchInsert(addAssetUri, valuesBuckets) > 0) {
        DataShare::DataSharePredicates predicates;
        DataShare::DataShareValuesBucket valuesBucket;
        valuesBucket.Put(MEDIA_DATA_DB_TITLE, MEDIA_SHARE_ALBUM_NAME);
        predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
        predicates.SetWhereArgs({ std::to_string(albumId) });
        std::string updateUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_ALBUMOPRN + "/" +
            MEDIA_ALBUMOPRN_MODIFYALBUM + "/" + std::to_string(albumId);
        Uri commitUri(updateUri);
        if (UserFileClient::Update(commitUri, predicates, valuesBucket) > 0) {
            DataShare::DataSharePredicates filePredicates;
            DataShare::DataShareValuesBucket fileValuesBucket;
            fileValuesBucket.Put(MEDIA_DATA_DB_BUCKET_NAME, MEDIA_SHARE_ALBUM_NAME);
            filePredicates.SetWhereClause(MEDIA_DATA_DB_BUCKET_ID + " = ? ");
            filePredicates.SetWhereArgs({ std::to_string(albumId) });
            Uri fileUri(MEDIALIBRARY_DATA_URI);
            UserFileClient::Update(fileUri, filePredicates, fileValuesBucket);
        }
    }
    
    RemoveFiles();
    return true;
}

bool SendManager::CopyFileToMediaAsset(const FileInfo &file, std::vector<std::string> &fileUris)
{
    std::string uri = UFM_CREATE_PHOTO;
    MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
    Uri createUri(uri);
    DataShare::DataShareValuesBucket valuesBucket;
    valuesBucket.Put(MEDIA_DATA_DB_NAME, file.name);
    std::string extention = MediaFileUtils::GetExtensionFromPath(file.newFileName);
    std::string mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extention);
    valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, static_cast<int>(MimeTypeUtils::GetMediaTypeFromMimeType(mimeType)));
    std::string fileUri;
    int fileId = UserFileClient::InsertExt(createUri, valuesBucket, fileUri);
    if (fileId < 0 || fileUri.empty()) {
        LOGE("failed to create media asset, error code is %{public}d", fileId);
        return false;
    }
    LOGI("fileId is %{public}d, fileUri is %{public}s", fileId, fileUri.c_str());
    fileUris.push_back(fileUri);

    int rfd = open(file.recvPath.c_str(), O_RDONLY | O_CLOEXEC);
    if (rfd < 0) {
        LOGE("rfd:%{public}d, path:%{public}s", rfd, file.recvPath.c_str());
        return false;
    }
    uri = fileUri;
    MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
    MediaFileUtils::UriAppendKeyValue(uri, MediaColumn::MEDIA_TIME_PENDING, std::to_string(UNCREATE_FILE_TIMEPENDING));
    Uri writeUri(uri);
    int wfd = UserFileClient::OpenFile(writeUri, Media::MEDIA_FILEMODE_WRITETRUNCATE);
    if (wfd <= 0) {
        LOGE("wfd:%{public}d, uri:%{public}s", wfd, fileUri.c_str());
        close(rfd);
        return false;
    }
    if (!MediaFileUtils::CopyFile(rfd, wfd)) {
        LOGE("send data failed. path:%{public}s, uri:%{public}s", file.recvPath.c_str(), fileUri.c_str());
        close(rfd);
        close(wfd);
        return false;
    }

    uri = UFM_CLOSE_PHOTO;
    MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
    MediaFileUtils::UriAppendKeyValue(uri, MediaColumn::MEDIA_TIME_PENDING, std::to_string(UNCLOSE_FILE_TIMEPENDING));
    Uri closeUri(uri);
    valuesBucket.Clear();
    valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
    valuesBucket.Put("create_thumbnail_sync_status", 1);
    int ret = UserFileClient::Insert(closeUri, valuesBucket);
    if (ret != 0) {
        LOGE("close failed. ret:%{public}d, path:%{public}s, uri:%{public}s", ret, file.recvPath.c_str(), fileUri.c_str());
        close(rfd);
        close(wfd);
        return false;
    }

    close(rfd);
    close(wfd);
    return true;
}
} // namespace FileShare
} // namespace OHOS